interface Options {
  /**
   * 自动显示到dom，并以此dom大小为显示大小，或者配置显示大小
   */
  el: string | HTMLElement;
  /**
   * （信号）样本的窗口大小。当执行快速傅里叶变换时，这些（信号）样本被用来获取频域数据。
   */
  fftSize?: number;
  /**
   * 画布的宽度
   */
  width?: number;
  /**
   * 画布的高度
   */
  height?: number;
}

class Spectrum {
  private configs: Required<Options> = {
    el: '',
    fftSize: 1024,
    width: 0,
    height: 0,
  }

  private canvas: HTMLCanvasElement | null = null;
  private ctx: CanvasRenderingContext2D | null = null;

  constructor(setOptions: Options) {
    for (const key in setOptions)
      (this.configs as any)[key] = (setOptions as any)[key];

    // 挂载canvas的元素
    let targetEle: HTMLElement | null = null;

    if (this.configs.el) {
      typeof this.configs.el === 'string' ? targetEle = document.querySelector(this.configs.el)
        : targetEle = this.configs.el;
    }

    if (targetEle) {
      !this.configs.width ? this.configs.width = targetEle.offsetWidth : undefined;
      !this.configs.height ? this.configs.height = targetEle.offsetHeight : undefined;
    } else throw new Error('未找到el属性的目标元素')

    this.mountedCanvas(targetEle);
  }

  private mountedCanvas(ele: HTMLElement): void {
    const { width, height } = this.configs;
    if (!width || !height) throw new Error("画布无宽高");

    const divEle: HTMLElement = document.createElement('div');
    divEle.innerHTML = `
      <div style="width: ${width}px;height: ${height}px;overflow: hidden;">
        <canvas width="${width}" height="${height}"></canvas>
      </div>
      `;
    this.canvas = divEle.querySelector('canvas');
    this.ctx = this.canvas?.getContext('2d')!;
    ele.appendChild(divEle);
    this.draw(new Uint8Array([128]))
  }

  draw(data: Uint8Array): void {
    const { width, height, fftSize } = this.configs;

    this.ctx?.clearRect(0, 0, width, height);
    this.ctx!.fillStyle = '#fff';
    this.ctx?.fillRect(0, 0, width, height);

    this.ctx!.lineWidth = 2;
    this.ctx!.strokeStyle = '#409EFF';

    this.ctx?.beginPath();

    const sliceWidth: number = width * 1.0 / fftSize;
    let x: number = 0;

    for (let i: number = 0; i < fftSize; i++) {

      const v: number = data[i] / 128.0;
      const y: number = v * height / 2;

      i === 0 ? this.ctx?.moveTo(x, y) : this.ctx?.lineTo(x, y)

      x += sliceWidth;
    }

    this.ctx?.lineTo(width, height / 2);
    this.ctx?.stroke();
  }

  destroyed(): Promise<void> {
    return new Promise(resolve => {
      this.canvas = null;
      this.ctx = null;
      // 挂载canvas的元素
      let targetEle: HTMLElement | null = null;

      if (this.configs.el)
        typeof this.configs.el === 'string' ? targetEle = document.querySelector(this.configs.el)
          : targetEle = this.configs.el;

      if (targetEle) targetEle.innerHTML = '';
      resolve();
    })
  }
}

export default Spectrum